package user

import (
	"strings"

	"system-admin/config/mysql"
	"system-admin/internal/define"
	"system-admin/internal/models"

	"192.168.1.75/go-pkg/errorx"
	"192.168.1.75/go-pkg/helper"
	"github.com/go-playground/validator/v10"
	"gorm.io/gorm"
)

// AllUser 所有用户
// 不显示管理员账号，防止管理员自己编辑自己
func AllUser(loginMerchantID string) (list interface{}, total int64) {
	var users []struct {
		ID       string `json:"id" gorm:"column:id"`
		UserName string `json:"username" gorm:"column:username"`
	}
	total = mysql.NewDB().Model(&models.User{}).
		Where("merchant_id = ?", loginMerchantID).
		Where("is_admin <> ?", 1).
		Where("is_super_admin <> ?", 1).
		Find(&users).
		RowsAffected
	list = users
	return
}

// UserList 用户列表
func UserList(loginMerchantID string, page, limit int) (interface{}, int64) {
	var users []struct {
		ID          string `json:"id" gorm:"column:id"`
		UserName    string `json:"username" gorm:"column:username"`
		Email       string `json:"email" gorm:"column:email"`
		RoleName    string `json:"role_name" gorm:"column:role_name"`
		RoleID      string `json:"role_id" gorm:"column:role_id"`
		CreatedAt   int64  `json:"created_at" gorm:"column:created_at"`
		UpdatedAt   int64  `json:"updated_at" gorm:"column:updated_at"`
		LatestLogin int64  `json:"latest_login" gorm:"column:latest_login"`
	}
	db := mysql.NewDB()

	// 公共条件
	tx := db.Model(&models.User{}).
		Where("user.merchant_id = ?", loginMerchantID).
		Where("user.deleted_at = ?", 0).
		Where("is_admin <> ?", 1).
		Where("is_super_admin <> ?", 1).
		Session(&gorm.Session{})

	// 用户数量
	var count int64
	tx.Count(&count)

	// 用户列表
	helper.Gorm{}.Paginate(tx, page, limit).
		Select(
			"user.id",
			"user.username",
			"user.email",
			"user.created_at",
			"user.updated_at",
			"user.latest_login",
			"role.id as role_id",
			"role.name as role_name",
		).
		Joins("LEFT JOIN role ON user.role_id = role.id").
		Find(&users)

	// 返回结果
	return users, count
}

// UserDetail 用户详情
func UserDetail(loginUserID string) interface{} {
	var detail struct {
		Username     string `json:"username" gorm:"column:username"`
		RoleName     string `json:"role_name" gorm:"column:role_name"`
		IsAdmin      int    `json:"is_admin" gorm:"column:is_admin"`
		IsSuperAdmin int    `json:"is_super_admin" gorm:"column:is_super_admin"`
		MerchantID   string `json:"merchant_id" gorm:"column:merchant_id"`
		LatestLogin  int64  `json:"latest_login" gorm:"column:latest_login"`
	}
	mysql.NewDB().Model(&models.User{}).
		Joins("LEFT JOIN role ON role.id = user.role_id").
		Select("user.username", "user.latest_login", "user.is_admin", "user.is_super_admin", "user.merchant_id", "role.name").
		Where("user.id = ?", loginUserID).
		Take(&detail)
	if loginUserID == "1" {
		detail.RoleName = "超级管理员"
	}
	return detail
}

// 新增用户
// merchantID为空，则同当前登录用户
func AddUser(loginUserID, roleID string, username string, passwd string, email string, isAdmin int) (string, error) {
	db := mysql.NewDB()
	// 去除空格
	username = strings.TrimSpace(username)
	passwd = strings.TrimSpace(passwd)
	roleID = strings.TrimSpace(roleID)
	// 参数检查
	if username == "" {
		return "", errorx.New("用户名不能为空", -1)
	}
	if passwd == "" {
		return "", errorx.New("密码不能为空", -1)
	}
	if roleID == "" {
		return "", errorx.New("角色不能为空", -1)
	}
	// 获取登录用户的信息
	var loginUser models.User
	db.Model(&models.User{}).Where("id = ?", loginUserID).Take(&loginUser)
	// 检查用户名是否已存在
	{
		var count int64
		db.Model(&models.User{}).
			Where(&models.User{
				Username: username,
			}).
			Count(&count)
		if count > 0 {
			return "", errorx.New("用户名已存在", -1)
		}
	}
	// 角色校验
	if roleID == "" {
		return "", errorx.New("角色不能为空", -1)
	} else {
		var count int64
		db.Model(&models.Role{}).Where("id = ?", roleID).Count(&count)
		if count <= 0 {
			return "", errorx.New("无效的角色", -1)
		}
	}
	validate := validator.New()
	// 新增用户
	var user models.User
	user.Username = username
	user.Password = generateEncryptPasswd(passwd)
	if email != "" {
		err := validate.Var(email, "email")
		if err != nil {
			return "", errorx.New("无效的邮箱", -1)
		}
		user.Email = email
	}
	user.MerchantID = loginUser.MerchantID
	user.RoleID = roleID
	user.IsAdmin = isAdmin
	rowsAffected := db.Model(&models.User{}).Create(&user).RowsAffected
	if rowsAffected <= 0 {
		return "", errorx.New("新增用户失败", -1)
	}
	return user.ID, nil
}

// EditUser 编辑用户
// 编辑角色
func EditUser(loginUserID string, userID string, roleID string, passwd string, email string, isAdmin int) error {
	db := mysql.NewDB()
	// 是否具有编辑权限
	if err := baseAuthCheck(loginUserID, userID); err != nil {
		return err
	}

	// 角色id合法性检查
	{
		var count int64
		db.Model(&models.Role{}).Where("id = ?", roleID).Count(&count)
		if count <= 0 {
			return errorx.New("角色不存在", -1)
		}
	}
	validate := validator.New()
	// 编辑用户
	{
		var user models.User
		user.RoleID = roleID
		if passwd != "" {
			user.Password = generateEncryptPasswd(passwd)
		}
		if email != "" {
			err := validate.Var(email, "email")
			if err != nil {
				return errorx.New("无效的邮箱", -1)
			}
			user.Email = email
		}
		user.IsAdmin = isAdmin
		rowsAffected := db.Model(&models.User{}).
			Where("id = ?", userID).
			Updates(&user).
			RowsAffected
		if rowsAffected <= 0 {
			return errorx.New("编辑用户失败", -1)
		}
	}
	return nil
}

// DeleteUser 删除用户
func DeleteUser(loginUserID string, userID string) error {
	db := mysql.NewDB()
	// 是否具有编辑权限
	if err := baseAuthCheck(loginUserID, userID); err != nil {
		return err
	}
	// 删除用户
	rowsAffected := db.Model(&models.User{}).Where("id = ?", userID).Delete(&models.User{}).RowsAffected
	if rowsAffected <= 0 {
		return errorx.New("删除失败", -1)
	}
	return nil
}

// DisableUser 禁用用户
func DisableUser(loginUserID string, userID string) error {
	db := mysql.NewDB()
	// 是否具有编辑权限
	if err := baseAuthCheck(loginUserID, userID); err != nil {
		return err
	}
	// 禁用用户
	rowsAffected := db.Model(&models.User{}).
		Where("id = ?", userID).
		Update("status", 2).
		RowsAffected
	if rowsAffected <= 0 {
		return errorx.New("禁用失败", -1)
	}
	return nil
}

// baseAuthCheck 基础权限检查
func baseAuthCheck(loginUserID string, userID string) error {
	db := mysql.NewDB()
	// 是否具有编辑权限
	{
		// 获取登录用户的信息
		var loginUser models.User
		db.Model(&models.User{}).Where("id = ?", loginUserID).Take(&loginUser)
		// 要编辑的用户的信息
		var editedUser models.User
		rowsAffected := db.Model(&models.User{}).Where("id = ?", userID).Take(&editedUser).RowsAffected
		if rowsAffected <= 0 {
			return errorx.New("用户不存在", -1)
		}
		// 超级管理员可以跨企业管理
		if loginUser.IsSuperAdmin == 1 {
			return nil
		}
		if loginUser.IsSuperAdmin != 1 && loginUser.MerchantID != editedUser.MerchantID {
			return errorx.New("只能编辑同个企业的用户", -1)
		}
	}
	return nil
}

// SetMerchantAdminUser 设置商户管理员用户
func SetMerchantAdminUser(loginUserID string, merchantID string, roleID string, username string, passwd string) error {
	db := mysql.NewDB()
	// 去掉空格
	merchantID = strings.TrimSpace(merchantID)
	roleID = strings.TrimSpace(roleID)
	username = strings.TrimSpace(username)
	passwd = strings.TrimSpace(passwd)

	// 检查角色是否存在
	if roleID != "" {
		var count int64
		db.Model(&models.Role{}).Where("id = ?", roleID).Count(&count)
		if count <= 0 {
			return errorx.New("角色不存在", -1)
		}
	}

	// 验证mechantID是否存在
	var merchant models.Merchant
	{
		rowsAffected := db.Model(&models.Merchant{}).Where(&models.Merchant{
			ID: merchantID,
		}).Take(&merchant).RowsAffected
		if rowsAffected <= 0 {
			return errorx.New("商户不存在", -1)
		}
	}

	// 获取登录用户的信息
	// 只能修改子商户
	var loginUser models.User
	db.Model(&models.User{}).Where("id = ?", loginUserID).Take(&loginUser)
	if merchant.PID != loginUser.MerchantID {
		return errorx.New("无权限", -1)
	}

	// 检查企业是否已经存在管理员
	var merchantUser models.User
	rowsAffected := db.Model(&models.User{}).
		Where(&models.User{
			MerchantID: merchantID,
			IsAdmin:    1,
		}).Take(&merchantUser).
		RowsAffected

	// 存在的可以更新
	var updatedUser models.User
	if rowsAffected > 0 {
		tx := db.Model(&models.User{}).Where(&models.User{
			ID: merchantUser.ID,
		})
		// 更新密码
		if passwd != "" {
			updatedUser.Password = generateEncryptPasswd(passwd)
		}
		// 更新角色
		if roleID != "" {
			updatedUser.RoleID = roleID
		}
		rowsAffected := tx.Updates(&updatedUser).RowsAffected
		if rowsAffected <= 0 {
			return errorx.New("设置商户管理员失败", -1)
		}
		// 不存在的新建
	} else {

		// 新增时，参数检查
		if username == "" {
			return errorx.New("用户名不能为空", -1)
		}
		if passwd == "" {
			return errorx.New("密码不能为空", -1)
		}
		if roleID == "" {
			return errorx.New("角色不能为空", -1)
		}

		// 判断用户名是否已经存在
		var count int64
		db.Model(&models.User{}).Where(&models.User{
			Username: username,
		}).Count(&count)
		if count > 0 {
			return errorx.New("用户名已经存在", -1)
		}
		// 启动事务
		tx := db.Begin()
		// 新增用户
		updatedUser.Username = username
		updatedUser.Password = generateEncryptPasswd(passwd)
		updatedUser.MerchantID = merchantID
		updatedUser.RoleID = roleID
		updatedUser.IsAdmin = 1
		rowsAffected := tx.Model(&models.User{}).Create(&updatedUser).RowsAffected
		if rowsAffected <= 0 {
			tx.Rollback()
			return errorx.New("设置商户管理员失败", -1)
		}
		// 更新商户管理员
		rowsAffected = tx.Model(&models.Merchant{}).
			Where("id = ?", merchantID).
			Update("admin_user_id", updatedUser.ID).
			RowsAffected
		if rowsAffected <= 0 {
			tx.Rollback()
			return errorx.New("设置商户管理员失败", -1)
		}
		// 提交事务
		tx.Commit()
	}
	return nil
}

// ModifyPassword 修改密码
func ModifyPassword(loginUserID string, password string, newPassword string, confirmPassword string) error {
	var count int64

	if password == "" {
		return errorx.New("密码不能为空", -1)
	}
	if newPassword == "" {
		return errorx.New("新密码不能为空", -1)
	}
	if confirmPassword == "" {
		return errorx.New("确认密码不能为空", -1)
	}

	mysql.NewDB().Model(&models.User{}).
		Where("id = ? AND password = ?", loginUserID, generateEncryptPasswd(password)).
		Count(&count)
	if count <= 0 {
		return errorx.New("用户名或密码错误", -1)
	}
	if newPassword != confirmPassword {
		return errorx.New("两次密码不一致", -1)
	}
	rowsAffected := mysql.NewDB().Model(&models.User{}).
		Where("id = ?", loginUserID).
		Update("password", generateEncryptPasswd(newPassword)).
		RowsAffected
	if rowsAffected <= 0 {
		return errorx.New("密码修改失败", -1)
	}
	return nil
}

// generateEncryptPasswd 生成加密的密码
func generateEncryptPasswd(passwd string) string {
	return helper.Md5(passwd + define.UserMd5Salt)
}
